//
//  NetWorkManager.m
//  IPDirectConnection
//
//  Created by lianglibao on 2019/4/20.
//  Copyright © 2019 lianglibao. All rights reserved.
//

#import "NetWorkManager.h"
#import "NetWorkRequestSerializer.h"
#import "FetchIPAdressManager.h"

@interface NetWorkManager ()<NSCopying, NSMutableCopying>
@property (nonatomic, strong) AFHTTPSessionManager *manager;
@end

@implementation NetWorkManager

// MARK: - sigleton instance
static NetWorkManager *_instance;
+ (instancetype)shareInstance {
	NetWorkManager *instance = [[self alloc] init];
	return instance;
}

- (instancetype)init {
	if (self = [super init]) {
		self.manager = [AFHTTPSessionManager manager];
		[self setupResponseSerializer];
		[self setupAuthAndRedirectionBlock];
	}
	return self;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
	if (!_instance) {
		static dispatch_once_t onceToken;
		dispatch_once(&onceToken, ^{
			_instance = [super allocWithZone:zone];
		});
	}
	return _instance;
}

- (id)copyWithZone:(NSZone *)zone {
	return _instance;
}

- (id)mutableCopyWithZone:(NSZone *)zone {
	return _instance;
}

// MARK: - setting
- (void)setupRequestSerializer {
	NetWorkRequestSerializer *requestSerializer = [NetWorkRequestSerializer serializer];
	self.manager.requestSerializer = requestSerializer;
}

- (void)setupResponseSerializer {
    AFHTTPResponseSerializer *serializer =  [AFHTTPResponseSerializer serializer];
    NSMutableSet *mSet = [NSMutableSet set];
    [mSet unionSet:serializer.acceptableContentTypes];
	[mSet addObject:@"text/css"];
    [mSet addObject:@"text/html"];
	[mSet addObject:@"application/javascript"];
	[mSet addObject:@"application/x-javascript"];
    serializer.acceptableContentTypes = mSet;
	self.manager.responseSerializer = serializer;
}

- (void)setupAuthAndRedirectionBlock {
    __weak typeof(self) weakSelf = self;
	[self.manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession * _Nonnull session, NSURLAuthenticationChallenge * _Nonnull challenge, NSURLCredential *__autoreleasing  _Nullable * _Nullable credential) {
        if (!challenge) {
            return NSURLSessionAuthChallengePerformDefaultHandling;
        }
        NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        /*
         * 获取原始域名信息。
         */
        NSString *host = [FetchIPAdressManager getHostWithIPAdress:challenge.protectionSpace.host];
        if (host) {
            NSLog(@"++++++++++++++host: %@", host);
        } else {
            host = challenge.protectionSpace.host;
        }

        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            if ([weakSelf.manager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:host]) {
                disposition = NSURLSessionAuthChallengeUseCredential;
            } else {
                disposition = NSURLSessionAuthChallengePerformDefaultHandling;
            }
        } else {
            disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        }
        return disposition;
    }];
    
    [weakSelf.manager setTaskDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession * _Nonnull session, NSURLSessionTask * _Nonnull task, NSURLAuthenticationChallenge * _Nonnull challenge, NSURLCredential *__autoreleasing  _Nullable * _Nullable credential) {
        if (!challenge) {
            return NSURLSessionAuthChallengePerformDefaultHandling;
        }
        NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        /*
         * 获取原始域名信息。
         */
        NSString *host = [[task.currentRequest allHTTPHeaderFields] objectForKey:@"host"];
        if (host) {
            NSLog(@"++++++++++++++host: %@", host);
        } else {
            host = challenge.protectionSpace.host;
        }
        
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            if ([weakSelf.manager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:host]) {
                disposition = NSURLSessionAuthChallengeUseCredential;
            } else {
                disposition = NSURLSessionAuthChallengePerformDefaultHandling;
            }
        } else {
            disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        }
        return disposition;
    }];
    
    [weakSelf.manager setTaskWillPerformHTTPRedirectionBlock:^NSURLRequest * _Nullable(NSURLSession * _Nonnull session, NSURLSessionTask * _Nonnull task, NSURLResponse * _Nonnull response, NSURLRequest * _Nonnull request) {
        NSMutableURLRequest *mRequest = [request mutableCopy];
        /*
         特别重要!!!
         使用IP直连的方式来加载URL或请求接口
         发生重定向时,由于设置的host为重定向前的原始host
         重定向后需要设置host为重定向后的host!
         */
        if (response) {
            [mRequest setValue:request.URL.host forHTTPHeaderField:@"host"];
            NSString *ip = [FetchIPAdressManager fetchIPAdressWithURL:request.URL];
            NSMutableString *mStr = [NSMutableString stringWithString:ip];
            if ([mStr containsString:@"?"]) {
                NSRange range = [mStr rangeOfString:@"?"];
                [mStr insertString:@"AspxAutoDetectCookieSupport=1&" atIndex:range.location+1];
            }
            mRequest.URL = [NSURL URLWithString:mStr];
            return mRequest;
        }
        return request;
    }];
}

// MARK: - public request methods
- (void)NetGET:(NSString *)path
	parameters:(nullable id)parameters
	   success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
	   failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure {
	NSMutableDictionary *parametersDict = [NSMutableDictionary dictionary];
	[parameters enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
		if ([obj isKindOfClass:NSDictionary.class]) {
			NSData *jsonData = [NSJSONSerialization dataWithJSONObject:obj options:0 error:nil];
			NSString *json = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
			[parametersDict setObject:json forKey:key];
		} else {
			[parametersDict setObject:obj forKey:key];
		}
	}];
	[self.manager GET:path parameters:[self handleQueryDict:parametersDict] progress:nil success:success failure:failure];
}

- (void)NetPOST:(NSString *)URLString
	 parameters:(nullable id)parameters
		success:(nullable void (^)(NSURLSessionDataTask *task, id responseObject))success
		failure:(nullable void (^)(NSURLSessionDataTask * __nullable task, NSError *error))failure {
	[self.manager POST:URLString parameters:[self handleQueryDict:parameters] progress:nil success:success failure:failure];
}


// 默认参数
- (NSDictionary *)handleQueryDict:(NSDictionary *)handleQueryDict {
    NSMutableDictionary *paramDic = [NSMutableDictionary dictionary];
    [handleQueryDict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key,
                                                   id _Nonnull obj,
                                                   BOOL *_Nonnull stop) {
        if (validString(obj) && validString(key)) {
            [paramDic setObject:obj forKey:key];
        }
    }];
    return paramDic;
}

// MARK: - Tools method and getters..
static inline NSString *validString(NSString *para) {
    return [para isKindOfClass:NSString.class] && para.length ? para : nil;
}

@end
